﻿// ManualRotator
// 
// Manual object table rotation class
// 
// When a rotation step is triggered, ManualRotator simply waits 
// for beepDelay milliseconds before firing StepDone.
// 
// The use case for this class is a object table that is manually
// rotated by the user. I.e. the user triggers a scan, and turns
// the object table by hand every time ManualRotator triggers a beep.
// 
// FLMScan - Featured by FabLab Munich

using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace FLMScan.Rotator
{
    class ManualRotator : IStepRotator
    {
        public enum BeepType
        {   ESimpleBeep = -1
        ,   ECriticalStopSound = 16
        ,   EAsteriskSound = 64
        ,   EExclamationSound = 48
        ,   EDefaultBeep = 0
        } ;

        private bool isDisposed = false;
        private int totalStepCount;
        private readonly int beepType;
        private readonly int beepDelay;
        private int currentStep;
        private const int DefaultTotalStepCount = 12;
        private const int DefaultBeepType = (int)BeepType.ESimpleBeep;

        private event EventHandler StepDone;

        event EventHandler IStepRotator.StepDone
        {
            add { StepDone += value; }
            remove { StepDone -= value; }
        }

        public ManualRotator()
        {
            beepType = DefaultBeepType;
            totalStepCount = DefaultTotalStepCount;
            currentStep = 0;
        }

        public ManualRotator(BeepType beepType, int beepDelay)
        {
            this.beepType = (int)beepType;
            this.beepDelay = beepDelay;
            totalStepCount = DefaultTotalStepCount;
            currentStep = 0;
        }

        public void Initialize()
        {
            // nothing to do here ... maybe do some special beep?
        }

        public bool IsConnected
        {
            // this "device" is always connected
            get { return true; }
        }

        public void SetTotalStepCount(int stepCount)
        {
            totalStepCount = stepCount;
        }

        public bool Step()
        {
            bool result = true;

            if (currentStep < totalStepCount)
            {
                MessageBeep(beepType);
                ++currentStep;

                Thread t = new Thread(new ThreadStart(DoStep));
                t.Start();
            }
            else
            {
                result = false;
            }

            return result;
        }

        public void Reset()
        {
            currentStep = 0;
        }

        private void DoStep()
        {
            Thread.Sleep(beepDelay);

            if (StepDone != null)
            {
                StepDone(this, EventArgs.Empty);
            }
        }

        [DllImport("user32")]
        static extern void MessageBeep(int type);

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool isDisposing)
        {
            if (isDisposed)
                return;

            if (isDisposing)
            {
                isDisposed = true;
                // nothing to do here
            }
        }  
    }
}
